package cn.arrow.note.validation.common.vo;


import cn.arrow.note.validation.common.enums.ResultCodeEnum;

import java.io.Serializable;

/**
 * 返回结果对象
 * <p>
 * 主要用于AJAX的前端请求或者是微服务的返回结果
 * </p>
 *
 * @author Walker
 **/

public class ResultObject<T> implements Serializable {

    private static final long serialVersionUID = -4534389991664735893L;

    /**
     * 操作是否成功，使用时候一般先通过这个判断，如果是失败的再根据code去判断到底是什么原因失败的
     */
    private Boolean success;

    /**
     * 状态编码，每种编码表示一种具体的状态
     */
    private String code;

    /**
     * 提示消息，这个可以作为调试或者前台展示的提示信息
     */
    private String msg;

    /**
     * 业务数据，如果执行成功，将返回具体的业务对象
     */
    private T data;

    private static final ResultObject SUCCESS = new ResultObject<>(true, ResultCodeEnum.SUCCESS.getMsg(), ResultCodeEnum.SUCCESS.getCode(), null);

    /**
     * 成功方法
     *
     * @param <T> 数据类型
     * @return 成功信息
     */
    public static <T> ResultObject<T> success() {
        return SUCCESS;
    }

    /**
     * 成功方法
     *
     * @param <T> 数据类型
     * @return 成功信息
     */
    public static <T> ResultObject<T> success(String msg) {
        return new ResultObject<>(true, msg, ResultCodeEnum.SUCCESS.getCode(), null);
    }

    /**
     * 成功方法
     *
     * @param data 数据
     * @param <T>  数据类型
     * @return 成功信息
     */
    public static <T> ResultObject<T> success(T data) {
        return new ResultObject<>(true, ResultCodeEnum.SUCCESS, data);
    }

    /**
     * 成功方法
     *
     * @param data 数据
     * @param <T>  数据类型
     * @param msg  提示信息
     * @return 成功信息
     */
    public static <T> ResultObject<T> success(T data, String msg) {
        return new ResultObject<>(true, msg, ResultCodeEnum.SUCCESS.getCode(), data);
    }

    /**
     * 失败方法
     *
     * @param resultCode 状态编码枚举
     * @param <T>        数据类型
     * @return 失败信息
     */
    public static <T> ResultObject<T> error(ResultCodeEnum resultCode) {
        return new ResultObject<>(false, resultCode, null);
    }

    /**
     * 失败方法
     *
     * @param msg  提示信息
     * @param code 编码
     * @param <T>  数据类型
     * @return 失败信息
     */
    public static <T> ResultObject<T> error(String msg, String code) {
        return new ResultObject<>(false, msg, code, null);
    }

    public static <T> Builder<T> builder() {
        return new Builder<>();
    }

    public static <T> Builder<T> builder(T data) {
        return new Builder<>(data);
    }

    /**
     * 构造器模式
     */
    public static class Builder<T> {
        private Boolean success;

        private String code;

        private String msg;

        private T data;

        Builder() {
        }

        Builder(T data) {
            this.data = data;
        }

        public Builder<T> success(Boolean success) {
            this.success = success;
            return this;
        }

        public Builder<T> code(String code) {
            this.code = code;
            return this;
        }

        public Builder<T> msg(String msg) {
            this.msg = msg;
            return this;
        }

        public Builder<T> data(T data) {
            this.data = data;
            return this;
        }

        public ResultObject<T> build() {
            return new ResultObject<>(this);
        }
    }

    private ResultObject(boolean success, String msg, String code, T data) {
        super();
        this.success = success;
        this.msg = msg;
        this.code = code;
        this.data = data;
    }

    private ResultObject(boolean success, ResultCodeEnum resultCode, T data) {
        super();
        this.success = success;
        this.msg = resultCode.getMsg();
        this.code = resultCode.getCode();
        this.data = data;
    }

    private ResultObject() {

    }

    public Boolean isSuccess() {
        return success;
    }

    public ResultObject<T> setSuccess(Boolean success) {
        this.success = success;
        return this;
    }

    public String getCode() {
        return code;
    }

    public ResultObject<T> setCode(String code) {
        this.code = code;
        return this;
    }

    public String getMsg() {
        return msg;
    }

    public ResultObject<T> setMsg(String msg) {
        this.msg = msg;
        return this;
    }

    public T getData() {
        return data;
    }

    public ResultObject<T> setData(T data) {
        this.data = data;
        return this;
    }

    private ResultObject(Builder<T> builder) {
        this.success = builder.success;
        this.code = builder.code;
        this.msg = builder.msg;
        this.data = builder.data;
    }

    @Override
    public String toString() {
        return "ResultEntity{" +
                "success=" + success +
                ", code=" + code +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                '}';
    }

}
